package com.yunjijia.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.yunjijia.shiro.MyShiroRealm;
import com.yunjijia.utils.MyExceptionResolver;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Configuration;

import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.servlet.HandlerExceptionResolver;

import java.util.LinkedHashMap;
import java.util.Map;




@Configuration
public class ShiroConfig {
    private final static Logger log = LoggerFactory.getLogger(ShiroConfig.class);

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //拦截器.
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();

        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/getGifCode", "anon");
        filterChainDefinitionMap.put("/ajaxLogin", "anon");
        filterChainDefinitionMap.put("/assets/**", "anon");
        filterChainDefinitionMap.put("/static/csslyl/**", "anon");
        filterChainDefinitionMap.put("/druid/*", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");

        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/", "user");
        filterChainDefinitionMap.put("/index", "user");
        filterChainDefinitionMap.put("/**", "authc");
//        filterChainDefinitionMap.put("/userInfoAdd", "authc,roles[admin]");

        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/warning");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
    //异常统一处理
    @Bean
    public HandlerExceptionResolver solver(){
        HandlerExceptionResolver handlerExceptionResolver =new MyExceptionResolver();
        return handlerExceptionResolver;
    }
    /**
     * cookie对象;
     * @return
     */
    @Bean
    public SimpleCookie rememberMeCookie(){
        System.out.println("ShiroConfiguration.rememberMeCookie()");
        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
        simpleCookie.setMaxAge(259200);
        return simpleCookie;
    }

    /**
     * cookie管理对象;
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        System.out.println("ShiroConfiguration.rememberMeManager()");
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        //设置realm.
        securityManager.setRealm(myShiroRealm());

        //注入缓存管理器;
        securityManager.setCacheManager(ehCacheManager());//这个如果执行多次，也是同样的一个对象;
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }


    /**
     * 身份认证realm;
     * (这个需要自己写，账号密码校验；权限等)
     * @return
     */
    @Bean
    public MyShiroRealm myShiroRealm(){
        MyShiroRealm myShiroRealm = new MyShiroRealm();
//		myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());;
        return myShiroRealm;
    }

    /**
     * 凭证匹配器
     * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
     *  所以我们需要修改下doGetAuthenticationInfo中的代码;
     * ）
     * @return
     */
//	@Bean
//	public HashedCredentialsMatcher hashedCredentialsMatcher(){
//		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//
//		hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
//		hashedCredentialsMatcher.setHashIterations(2);//散列的次数，比如散列两次，相当于 md5(md5(""));
//
//		return hashedCredentialsMatcher;
//	}
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    /**
     * 添加ShiroDialect 为了在thymeleaf里使用shiro的标签的bean
     * @return
     */
    @Bean(name = "shiroDialect")
    public ShiroDialect getShiroDialect(){
        ShiroDialect shiroDialect = new ShiroDialect();
        return shiroDialect;
    }


    /**
     * shiro缓存管理器;
     * 需要注入对应的其它的实体类中：
     * 1、安全管理器：securityManager
     * 可见securityManager是整个shiro的核心；
     * @return
     */
    @Bean
    public EhCacheManager ehCacheManager(){
        System.out.println("ShiroConfiguration.getEhCacheManager()");
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
        return cacheManager;
    }



}
//
//    /**
//     * 说白了就是 像拦截器一样 先配置好 然后访问的时候先拦截
//     *  拦截后认证 数据库对比 然后授权 在跳转
//     * 一、在认证中：
//     * 1.1，将加密算法定义好后扔到 MyShiroRealm中 也就是自己定义的realm中
//     * 1.2，将MyShiroRealm定义后扔到SecurityManager中。
//     * 1.3，后期用到session什么的，都被SecurityManager管理
//     *
//     */
//
//
//    private MyRealm myRealm;
//    private SessionDaoConfig sessionDaoConfig;
//
////        @Bean("shirFilter")
////        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager securityManager) {
////            ShiroFilterFactoryBean shiro = new ShiroFilterFactoryBean();
////            shiro.setLoginUrl("/unlogin");  //没有登陆的json返回
////            shiro.setUnauthorizedUrl("/no");    //没有权限的json返回
////            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
////            // 配置不会被拦截的链接 顺序判断
////            filterChainDefinitionMap.put("/static/**", "anon");
////            filterChainDefinitionMap.put("/ajaxLogin", "anon");
////            filterChainDefinitionMap.put("/map", "anon");
////            filterChainDefinitionMap.put("/login", "anon");
////            //注意,如果roles[admin,guest]是用户需要同时包含两者角色才可以访问,是且的关系;
////            //如果想改为或的关系,请继承AuthorizationFilter并加入过滤连,perm资源也是一样,需要继承PermissionsAuthorizationFilter加入过滤链;
////            filterChainDefinitionMap.put("/test", "authc,roles[admin]");
////            filterChainDefinitionMap.put("/**", "authc");
////            shiro.setFilterChainDefinitionMap(filterChainDefinitionMap);
////            shiro.setSecurityManager(securityManager);
////            return shiro;
////        }
//
//
//    @Value("${spring.redis.host}")
//    private String host;
//
//    @Value("${spring.redis.port}")
//    private int port;
//
//    @Value("${spring.redis.password}")
//    private String password;
//
//    @Value("${spring.redis.timeout}")
//    private int timeout;
//
//    @Bean("shirFilter")
//    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
//
//        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
//        factoryBean.setSecurityManager(securityManager);
//        factoryBean.setLoginUrl("/notLogin");
//        factoryBean.setUnauthorizedUrl("/notRole");
//        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//        filterChainDefinitionMap.put("/guest/**", "anon");
//        filterChainDefinitionMap.put("/user/**", "roles[user]");
//        filterChainDefinitionMap.put("/admin/**", "roles[admin]");
//        filterChainDefinitionMap.put("/user-info/login", "anon");
//        filterChainDefinitionMap.put("/**", "authc");
//        factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
//        factoryBean.setSecurityManager(securityManager);
//        return factoryBean;
//
//    }
//
//    @Bean
//    public HashedCredentialsMatcher hashedCredentialsMatcher() {
//        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//        credentialsMatcher.setHashAlgorithmName("MD5"); //加密方式
//        credentialsMatcher.setHashIterations(2);//散列次数
//        return credentialsMatcher;
//    }
//
//    //自定义的类
////    @Bean
////    public CustomRealm customRealm() {
////        CustomRealm customRealm = new CustomRealm();
////        customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
////        customRealm.setAuthenticationCachingEnabled(true);
////        customRealm.setAuthorizationCachingEnabled(true);
////        return customRealm;
////    }
//
//    // RedisManager 插件
//    public RedisManager redisManager() {
//        RedisManager redisManager = new RedisManager();
//        log.info("redis:host" + host);
//        redisManager.setHost(host);
//        redisManager.setPort(port);
//        redisManager.setTimeout(timeout);
//        if (StringUtils.isNotBlank(password))
//            redisManager.setPassword(password);
//
//        return redisManager;
//    }
//
//    public RedisCacheManager cacheManager() {
//        RedisCacheManager redisCacheManager = new RedisCacheManager();
//        redisCacheManager.setRedisManager(redisManager());
//        return redisCacheManager;
//    }
//
//    @Bean
//    public SecurityManager securityManager() {
////        DefaultWebSecurityManager defaultSecurityManager = new
////                DefaultWebSecurityManager();
////        defaultSecurityManager.setRealm(myRealm);
////        defaultSecurityManager.setCacheManager(cacheManager());
////        defaultSecurityManager.setSessionManager(sessionManager());
////        defaultSecurityManager.setRememberMeManager(rememberMeManager());
////        return defaultSecurityManager;
//        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//        securityManager.setRealm(myRealm);
//        return securityManager;
//
////        DefaultWebSecurityManager def = new DefaultWebSecurityManager();
////        def.setRealm(myRealm);
////        // 自定义session管理 使用redis
////        SessionConfig sessionConfig = new SessionConfig();
////        sessionConfig.setSessionDAO(sessionDaoConfig);
////        //sessionConfig.setSessionDAO(new SessionDaoConfig());
////        def.setSessionManager(sessionConfig);
////        // 自定义缓存实现 使用redis
////        //def.setCacheManager();
////        return def;
//
//
//    }
//
//    private SimpleCookie rememberMeCookie() {
//        // 设置 cookie 名称，对应 login.html 页面的 <input type="checkbox" name="rememberMe"/>
//        SimpleCookie cookie = new SimpleCookie("rememberMe");
//        // 设置 cookie 的过期时间，单位为秒 一个月
//        cookie.setMaxAge(3600 * 30);
//        return cookie;
//    }
//
//    private CookieRememberMeManager rememberMeManager() {
//        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
//        cookieRememberMeManager.setCookie(rememberMeCookie());
//        // rememberMe cookie 加密的密钥
//        cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
//        return cookieRememberMeManager;
//    }
//
//
//    // RedisSessionDao 插件
//    @Bean
//    public RedisSessionDAO redisSessionDAO() {
//        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
//        redisSessionDAO.setRedisManager(redisManager());
//        return redisSessionDAO;
//    }
//
//    /**
//     * Session 管理
//     *
//     * @return
//     */
////    @Bean
////    public DefaultWebSessionManager sessionManager() {
////        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
////        defaultWebSessionManager.setSessionDAO(redisSessionDAO());
////        defaultWebSessionManager.setGlobalSessionTimeout(3600 * 1000);//单位毫秒
////        defaultWebSessionManager.setSessionIdUrlRewritingEnabled(false);
////        return defaultWebSessionManager;
////    }
//
//
//    // 开启 shiro aop 注解模式  注意需要注解依赖
//    @Bean
//    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
//        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
//        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
//        return authorizationAttributeSourceAdvisor;
//    }
//
//    //生命周期处理器
//    @Bean
//    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
//        return new LifecycleBeanPostProcessor();
//    }
//}




